from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext import db
import os

from html import CheckBox, DropDown, MultiSelect #importing the html wrappers.
import validate #import validation
import tables
import main
import datetime
import staticInits 
import cgi #for escaping html chars in forms
import re

globalEid = "default"

class TableEntry(object):
    '''
    TableEntry will be used in renderTemplate.  It will set the values for each row in the table.
    '''
    def __init__(self, number, field, information, exampleInput = ""):
        self.number = number
        self.field = field
        self.information = information
        self.exampleInput = exampleInput 

class taApp(webapp.RequestHandler):
    '''
    taApp contains the get, post and renderTemplate functions
    '''
    
    def __init__(self):

        webapp.RequestHandler.__init__(self) #calling the parent constructor, A MUST!
        

        #DB CALLS
        (self.majors, self.languages, self.specializations, self.courses, self.taHistory) = (dict(), dict(), dict(), dict(), dict())
        #building dictionaries, keyed with name attributes which are gauranteed unique to each entry
        for row in db.GqlQuery("SELECT * FROM Major"): self.majors[row.name] = row
        for row in db.GqlQuery("SELECT * FROM Language"): self.languages[row.name] = row
        for row in db.GqlQuery("SELECT * FROM Specialization"): self.specializations[row.name] = row
        for row in db.GqlQuery("SELECT * FROM Course"): self.courses[row.name] = row
        for row in db.GqlQuery("SELECT * FROM Course"): self.taHistory[row.name] = row
        
        self.phdMasters = ["PhD", "Masters"]       
        self.citizenResident = ["Citizen", "Resident"]
        self.nativeEnglishSpeaker = ["yes", "no"]
        
        #fetching current state
        self.currentState = tables.AppState.get_by_key_name('currentState')
        self.currentSemester = self.currentState.semester
        
        #getting the current applicant's info from the database
        #self.currentTa = db.GqlQuery("SELECT * FROM Ta WHERE eid = :eid", eid = self.eid)
    
        #dict used in get method
        self.origForm = dict()
        self.origForm['First Name'] = '''<input type="text" name="firstName">'''# value=''' + currentTa.firstName + '''>'''
        self.origForm['Last Name'] = '''<input type="text" name="lastName">'''
        self.origForm['Phone Number'] = '''<table align="center"><tr><td>( <input type="text" name="phone1" size="3" maxlength="3"> )</td><td> - <input type="text" name="phone2" size="3" maxlength="3"> </td><td>- <input type="text" name="phone3" size="4" maxlength="4"></td></tr></table>'''
        self.origForm['Email'] = '''<input type="text" name="email">'''
        self.origForm['Major'] = DropDown(self.majors, name="Major")
        self.origForm['Admission Date'] = '''<table align="center"><tr><td><input type="text" name="month" size="2" maxlength="2"></td><td><input type="text" name="day" size="2" maxlength="2"></td><td><input type="text" name="year" size="4" maxlength="4"></td></tr></table>'''
        self.origForm['Phd/Masters'] = DropDown(self.phdMasters, name="Phd/Masters")
        self.origForm['Supervising Professor'] =  '''<input type="text" name="Supervising Professor">'''
        self.origForm['Citizen/Resident'] = DropDown(self.citizenResident, name="Citizen/Resident")
        self.origForm['Native English Speaker'] = DropDown(self.nativeEnglishSpeaker, name="Native English Speaker")
        self.origForm['TA History'] = MultiSelect(self.taHistory, name="TA History")
        self.origForm['Programming Languages'] = MultiSelect(self.languages, name="Programming Languages")
        self.origForm['Area of Specialization'] = MultiSelect(self.specializations, name="Area of Specialization")
        self.origForm['Courses Qualified to Teach'] = MultiSelect(self.courses, name="Courses Qualified to Teach")
    
    def get(self):
        self.redirect('/login')
        
    def post(self):

    
        clicked = self.request.get("submit")
        blanksAllowed = clicked == "Save"


        eid = self.request.get('eid', default_value="default").lower()
        if eid != "default":
            global globalEid
            globalEid = eid
            self.response.out.write('eid: '+eid+'<br>')
            #only bring up the application form if the time is correct!
            #getting the applicant's info from the database
            for ta in db.GqlQuery("SELECT * FROM Ta WHERE eid = :TAeid", TAeid = eid): currentTa = ta 

            self.origForm['First Name'] = currentTa.firstName + '''<input type="hidden" name="firstName" value=''' + currentTa.firstName + '''>'''
            self.origForm['Last Name'] = currentTa.lastName + '''<input type="hidden" name="lastName" value=''' + currentTa.lastName + '''>'''

            if currentTa.phone != "" and currentTa.phone != None:
                self.origForm['Phone Number'] = '''<table align="center"><tr><td>( <input type="text" name="phone1" value=''' + currentTa.phone[0:3] + ''' size="3" maxlength="3"> )</td><td> - <input type="text" name="phone2" value=''' + currentTa.phone[3:6] + ''' size="3" maxlength="3"> </td><td>- <input type="text" name="phone3" value=''' + currentTa.phone[6:] + ''' size="4" maxlength="4"></td></tr></table>'''
            else:
                self.origForm['Phone Number'] = '''<table align="center"><tr><td>( <input type="text" name="phone1" value="" size="3" maxlength="3"> )</td><td> - <input type="text" name="phone2" value="" size="3" maxlength="3"> </td><td>- <input type="text" name="phone3" value="" size="4" maxlength="4"></td></tr></table>'''

            self.origForm['Email'] = '''<input type="text" name="email" value=''' + currentTa.email + '''>''' if currentTa.email is not None else '''<input type="text" name="email" value="">'''

            if currentTa.major is not None:                
                self.origForm['Major'] = DropDown(self.majors, selected = currentTa.major.name, name="Major")
            
            currentTa.admissionDate = datetime.date(1,1,1) if currentTa.admissionDate is None else currentTa.admissionDate
            if currentTa.admissionDate.year != 1:
                tempMonth = "0" + str(currentTa.admissionDate.month)
                tempDay = "0" + str(currentTa.admissionDate.day)
                self.origForm['Admission Date'] = '''<table align="center"><tr><td><input type="text" name="month" value=''' + tempMonth[-2:] + ''' size="2" maxlength="2"></td><td><input type="text" name="day" value=''' + tempDay[-2:] + ''' size="2" maxlength="2"></td><td><input type="text" name="year" value=''' + str(currentTa.admissionDate.year) + ''' size="4" maxlength="4"></td></tr></table>'''
            else:
                self.origForm['Admission Date'] = '''<table align="center"><tr><td><input type="text" name="month" value="" size="2" maxlength="2"></td><td><input type="text" name="day" value="" size="2" maxlength="2"></td><td><input type="text" name="year" value="" size="4" maxlength="4"></td></tr></table>'''

            self.origForm['Phd/Masters'] = DropDown(self.phdMasters, selected = currentTa.degree, name="Phd/Masters")
            if currentTa.supervisor == None:
                supervisor = ''
            else:
                supervisor = currentTa.supervisor
            self.origForm['Supervising Professor'] =  '''<input type="text" name="Supervising Professor" value="''' + supervisor + '''">'''
            if currentTa.residency is not None:
                if currentTa.residency == True : #switch the boolean value to the corresponding string
                    temp = "Citizen"
                elif currentTa.residency == False:
                    temp = "Resident"
                self.origForm['Citizen/Resident'] = DropDown(self.citizenResident, selected = temp, name="Citizen/Resident")
            else:
                self.origForm['Citizen/Resident'] = DropDown(self.citizenResident, name="Citizen/Resident")
            if currentTa.nativeEnglish is not None:
                if currentTa.nativeEnglish == True : #switch the boolean value to the corresponding string
                    temp = "yes"
                else:
                    temp = "no"
                self.origForm['Native English Speaker'] = DropDown(self.nativeEnglishSpeaker, selected = temp, name="Native English Speaker")
            else:
                self.origForm['Native English Speaker'] = DropDown(self.nativeEnglishSpeaker, name="Native English Speaker")
            self.origForm['TA History'] = MultiSelect(self.taHistory, selected = [history.taHistory.name for history in db.GqlQuery("SELECT * FROM TaTaHistory WHERE ta = :ta", ta = currentTa)], name="TA History")
            self.origForm['Programming Languages'] = MultiSelect(self.languages, selected = [languages.language.name for languages in db.GqlQuery("SELECT * FROM TaLanguage WHERE ta = :ta", ta = currentTa)], name="Programming Languages")
            self.origForm['Area of Specialization'] = MultiSelect(self.specializations, selected = [special.specialization.name for special in db.GqlQuery("SELECT * FROM TaSpecialization WHERE ta = :ta", ta = currentTa)], name="Area of Specialization")
            self.origForm['Courses Qualified to Teach'] = MultiSelect(self.courses, selected = [qual.qualification.name for qual in db.GqlQuery("SELECT * FROM TaQualification WHERE ta = :ta", ta = currentTa)], name="Courses Qualified to Teach")
                    
            if self.currentState.time.name == 'Ta Apply' :
                self.renderTemplate(self.origForm)
            else:
                self.response.out.write(staticInits.notTimeStr(verb = 'applying'))
            return
        '''
        Uses the user's input for the table and validates the origFormrmation the user enters.  If only of the origFormrmation is valid, then the page will tell the user which fields are incorrect and will make the fields with valid origFormrmation sticky.  This is done individually for each field in the same block of code following the validation. 
        '''
        self.postForm = self.origForm.copy() #dict used in post method
    
        #a dict to hold the validated entries
        validated = dict()
        notRequired = dict()

        #variables for 
        languageSelect = False
        specializationSelect = False
        qualifiedSelect = False
        supervisorSelect = False
        taHistorySelect = False

        #validate first and last name
        firstName = cgi.escape(self.request.get('firstName'))
        lastName = cgi.escape(self.request.get('lastName'))
        validFirst = False
        if validate.validateFirstName(firstName) or (firstName == '' and blanksAllowed):
            validFirst = True
            validated['First Name'] = firstName #add firstName to validated list
            self.postForm['First Name'] = firstName+ '''<input type="hidden" name="firstName" value=''' + firstName + '''>'''
        
        validLast = False
        if validate.validateLastName(lastName) or (lastName == '' and blanksAllowed):
            validLast = True
            validated['Last Name'] = lastName #add lastName to validated list
            self.postForm['Last Name'] = lastName+ '''<input type="hidden" name="lastName" value=''' + lastName + '''>'''
        
        #validation for the phone number
        phone1 = cgi.escape(self.request.get('phone1'))
        phone2 = cgi.escape(self.request.get('phone2'))
        phone3 = cgi.escape(self.request.get('phone3'))
        validPhone = False
        if validate.digit(phone1, count=3) and validate.digit(phone2, count=3) and validate.digit(phone3, count=4) or ((phone1=='' and phone2=='' and phone3=='') and blanksAllowed):
            validPhone = True
            validated['Phone Number'] = [phone1, phone2, phone3] #add phone number to validated list
            self.postForm['Phone Number'] = '''<table align="center"><tr><td>( <input type="text" name="phone1" value="''' + phone1 + '''" size="3" maxlength="3"> )</td><td> - <input type="text" name="phone2" value="''' + phone2 + '''" size="3" maxlength="3"> </td><td>- <input type="text" name="phone3" value="''' + phone3 + '''" size="4" maxlength="4"></td></tr></table>'''
            
        #validate email
        validEmail = False
        email = cgi.escape(self.request.get('email'))
        if validate.validateEmail(email) or (email=='' and blanksAllowed):
            validEmail = True
            validated['Email'] = email #add email to validated list
            self.postForm['Email'] = '''<input type="text" name="email" value=''' + email + '''>'''            
         
        #validate Date
        month = cgi.escape(self.request.get('month'))
        day = cgi.escape(self.request.get('day'))
        year = cgi.escape(self.request.get('year'))
        validDate = False        
        if validate.digit(month, count=2, lessThan=13) and validate.digit(day, count=2, lessThan=32) and validate.digit(year, count=4, lessThan=(self.currentSemester.year+1)) or ((month=='' and day=='' and year=='') and blanksAllowed) :
            validDate = True
            validated['Admission Date'] = [month, day, year] #add admission date to validated list
            self.postForm['Admission Date'] = '''<table align="center"><tr><td><input type="text" name="month" value="''' + month + '''" size="2" maxlength="2"></td><td><input type="text" name="day" value="''' + day + '''" size="2" maxlength="2"></td><td><input type="text" name="year" value="''' + year + '''" size="4" maxlength="4"></td></tr></table>'''

        if validFirst is not True :
            assert not validate.validateFirstName(firstName)
            self.response.out.write('<font color="red">Please enter a valid first name.</font><br />')
        if validLast is not True :
            assert not validate.validateLastName(lastName)
            self.response.out.write('<font color="red">Please enter a valid last name.</font><br />')
        if validPhone is not True :
            assert not validate.digit(phone1, count=3) or not validate.digit(phone2, count=3) or not validate.digit(phone3, count=3)
            self.response.out.write('<font color="red">Please enter a valid phone number.</font><br />')
        if validEmail is not True :
            assert not validate.validateEmail(email)
            self.response.out.write('<font color="red">Please enter a valid email address.</font><br />')
        if validDate is not True :
            self.response.out.write('<font color="red">Please enter a valid admissions date.</font><br />')

        #validate supervising prof
        profName = re.split('\s+', cgi.escape(self.request.get('Supervising Professor'))) #split by whitespace 
        validName = False
        if(len(profName) == 2):
            validFirst = validate.validateFirstName(profName[0])
            validLast = validate.validateLastName(profName[1])
            validName = validFirst and validLast
        if(validName):
            supervisorSelect = True
            notRequired['Supervising Professor'] = profName[0] + ' ' + profName[1]
            self.postForm['Supervising Professor'] = '''<input type="text" name="Supervising Professor" value="''' + profName[0] + ' ' + profName[1] + '''">'''
        
        #validating dropdowns and multiselects
        for key in self.origForm:
            value = self.origForm[key]
            input = self.request.get_all(key)
            assert type(input) == type(list())
            
            if type(value) == type(DropDown()):
                assert len(input) == 1 #only one option for dropdown, cant multiselect
                input = input[0]
                
                assert type(input) == type(unicode())
                
                if validate.dropDown(input) or (str(input) == '--make selection--' and blanksAllowed):
                    validated[key] = input
                    self.postForm[key] = DropDown(options = value.options, selected = input, name = key)
                else:                    
                    self.response.out.write('<font color="red">Please make a selection for ' + key + '.</font><br />')
            elif type(value) == type(MultiSelect()):
                if len(input) != 0:
                    if key == "Programming Languages" :
                        notRequired[key] = input
                        languageSelect = True
                    if key == "Area of Specialization" :
                        notRequired[key] = input
                        specializationSelect = True
                    if key == "Courses Qualified to Teach" :
                        notRequired[key] = input
                        qualifiedSelect = True
                    if key == "TA History" :
                        notRequired[key] = input
                        taHistorySelect = True
                    self.postForm[key] = MultiSelect(options = value.options, selected = input, name = key)                

        #if validated has elements, then field has passed validation so add them to the database.
        if len(validated) is 9 :      
            
            #delete the ta from the database so that it can be added back in (with no duplicates)
            q = db.GqlQuery("SELECT * FROM Ta WHERE eid = :TAeid", TAeid = globalEid)
            #db.delete(q)


            phoneNumber = ''
            #convert the phone number from a list to a string for the database
            for x in validated['Phone Number'] : #blank if all blanks
                phoneNumber += x

            dateYear = 1
            #maybe wont need this....hopefully
            dateDate = validated['Admission Date']
            if dateDate[0] != "":
                dateDay = int(dateDate[1])
                dateMonth = int(dateDate[0])
                dateYear = int(dateDate[2])

            #create the ta!
            #temporarily made key_name equal to a string of the first and last name
            for ta in q:
                ta.firstName = validated['First Name']            
                ta.lastName=validated['Last Name']
                ta.phone=phoneNumber
                ta.email=validated['Email']
                ta.major=self.majors[self.request.get('Major')] if self.request.get('Major') != "--make selection--" else None
                ta.admissionDate=datetime.date(dateYear,dateMonth,dateDay) if dateYear != 1 else datetime.date(1,1,1) #all ones if dat
                ta.degree=validated['Phd/Masters']
                ta.residency=True if validated['Citizen/Resident'] == 'Citizen' else False
                ta.nativeEnglish=True if validated['Native English Speaker'] == 'yes' else False
                ta.semester = self.currentSemester
                ta.eid = globalEid
                if supervisorSelect :
                    ta.supervisor = notRequired['Supervising Professor']
                ta.submitted = not blanksAllowed
                ta.put()
        
                q = db.GqlQuery("SELECT * FROM TaTaHistory WHERE ta = :ta", ta = ta)
                db.delete(q)
                q = db.GqlQuery("SELECT * FROM TaQualification WHERE ta = :ta", ta = ta)
                db.delete(q)
                q = db.GqlQuery("SELECT * FROM TaLanguage WHERE ta = :ta", ta = ta)
                db.delete(q)
                q = db.GqlQuery("SELECT * FROM TaSpecialization WHERE ta = :ta", ta = ta)
                db.delete(q)
            
                #loops for multislects (many to many relations)
                if taHistorySelect :
                    for instructor in notRequired['TA History']: tables.TaTaHistory(taHistory = self.taHistory[instructor], ta = ta).put()
                if qualifiedSelect :
                    for course in notRequired['Courses Qualified to Teach']: tables.TaQualification(qualification = self.courses[course], ta = ta).put()
                if languageSelect :
                    for language in notRequired['Programming Languages']: tables.TaLanguage(language = self.languages[language], ta = ta).put()                
                if specializationSelect :
                    for area in notRequired['Area of Specialization']: tables.TaSpecialization(specialization = self.specializations[area], ta = ta).put()
            if clicked == "Submit":        
                #once everything has been added, tell the user that his application was accepted
                self.response.out.write("Application added! Thanks! <br />")
            else:
                self.response.out.write("<font color = red> Application saved. </font><br> <br />")
                self.renderTemplate(self.postForm)
        else : #if everything in the form is not valid
            self.renderTemplate(self.postForm)

    def renderTemplate(self, form): 
        '''
        renderTemplate uses TableEntry to create the entries for the table
        '''
        semester = self.currentState.semester        
       
        table = [
            TableEntry("1.", "First Name *:", form['First Name']),
            TableEntry("2.", "Last Name *:", form['Last Name']),
            TableEntry("3.", "Phone Number *:", form['Phone Number'], "<i>### - ### - ####</i>"),
            TableEntry("4.", "Email *:", form['Email'], "<i>user@domain.com</i>"),
            TableEntry("5.", "Major Field *:", form['Major']),
            TableEntry("6.", "Admission Date *:", form['Admission Date'], "<i>MM-DD-YYYY</i>"),
            TableEntry("7.", "Phd/Masters *:", form['Phd/Masters']),
            TableEntry("8.", "Supervising Professor:", form['Supervising Professor']),
            TableEntry("9.", "Citizen/Resident *:", form['Citizen/Resident']),
            TableEntry("10.", "Native English Speaker *:", form['Native English Speaker']),
            TableEntry("11.", "TA History :", form['TA History']),
            TableEntry("12.", "Programming Languages:", form['Programming Languages']),
            TableEntry("13.", "Area of Specialization:", form['Area of Specialization']),
            TableEntry("14.", "Courses Qualified to Teach:", form['Courses Qualified to Teach']),
            ]
        
        #setting up template dictionary
        templateValues = {
            'table': table,
            'semester': semester
        }
        
        #telling it to use the template
        path = os.path.join(os.path.dirname(__file__), 'ta.html')
        self.response.out.write(template.render(path, templateValues))
        

application = webapp.WSGIApplication([('/ta', taApp)], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()
